Passthrough: disable bus-mastering on any card that causes an IOMMU fault.
authorTim Deegan <Tim.Deegan@citrix.com>
Fri, 12 Aug 2011 10:29:24 +0000 (11:29 +0100)
committerTim Deegan <Tim.Deegan@citrix.com>
Fri, 12 Aug 2011 10:29:24 +0000 (11:29 +0100)
This stops the card from raising back-to-back faults and live-locking
the CPU that handles them.

Signed-off-by: Tim Deegan <tim@xen.org>
Acked-by: Wei Wang2 <wei.wang2@amd.com>
Acked-by: Allen M Kay <allen.m.kay@intel.com>
xen/drivers/passthrough/amd/iommu_init.c
xen/drivers/passthrough/vtd/iommu.c

index bbf8908d74b8d6d85b0052e17400f5a2a53602c9..6bff49ada55168f7e4d57bf7375d401de3f30d5c 100644 (file)
@@ -461,7 +461,7 @@ static hw_irq_controller iommu_msi_type = {
 
 static void parse_event_log_entry(u32 entry[])
 {
-    u16 domain_id, device_id;
+    u16 domain_id, device_id, bdf, cword;
     u32 code;
     u64 *addr;
     char * event_str[] = {"ILLEGAL_DEV_TABLE_ENTRY",
@@ -496,6 +496,18 @@ static void parse_event_log_entry(u32 entry[])
                "%s: domain = %d, device id = 0x%04x, "
                "fault address = 0x%"PRIx64"\n",
                event_str[code-1], domain_id, device_id, *addr);
+
+        /* Tell the device to stop DMAing; we can't rely on the guest to
+         * control it for us. */
+        for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
+            if ( get_requestor_id(bdf) == device_id ) 
+            {
+                cword = pci_conf_read16(PCI_BUS(bdf), PCI_SLOT(bdf), 
+                                PCI_FUNC(bdf), PCI_COMMAND);
+                pci_conf_write16(PCI_BUS(bdf), PCI_SLOT(bdf), 
+                                 PCI_FUNC(bdf), PCI_COMMAND, 
+                                 cword & ~PCI_COMMAND_MASTER);
+            }
     }
     else
     {
index 23c6f2f1eb969752d0460a99fd22037918abdda8..91e8c3b3b4c3f4b175dd96212a6f87de7450dea7 100644 (file)
@@ -884,7 +884,7 @@ static void iommu_page_fault(int irq, void *dev_id,
     while (1)
     {
         u8 fault_reason;
-        u16 source_id;
+        u16 source_id, cword;
         u32 data;
         u64 guest_addr;
         int type;
@@ -917,6 +917,14 @@ static void iommu_page_fault(int irq, void *dev_id,
         iommu_page_fault_do_one(iommu, type, fault_reason,
                                 source_id, guest_addr);
 
+        /* Tell the device to stop DMAing; we can't rely on the guest to
+         * control it for us. */
+        cword = pci_conf_read16(PCI_BUS(source_id), PCI_SLOT(source_id), 
+                                PCI_FUNC(source_id), PCI_COMMAND);
+        pci_conf_write16(PCI_BUS(source_id), PCI_SLOT(source_id), 
+                         PCI_FUNC(source_id), PCI_COMMAND, 
+                         cword & ~PCI_COMMAND_MASTER);
+
         fault_index++;
         if ( fault_index > cap_num_fault_regs(iommu->cap) )
             fault_index = 0;